package CCN::MGW;
# (c) 2007, Stephane Alnet
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
use strict; use warnings;
use base 'CGI::Application';
use HTML::Template;

sub setup
{
    my $self = shift;
    $self->start_mode('show_index');
    $self->mode_param('_method');
    $self->run_modes(
        'show_index'        => 'show_index',
        'show_cards'        => 'show_cards',
        'apply_cards'       => 'apply_cards',
        'show_ethernet'     => 'show_ethernet',
        'apply_ethernet'    => 'apply_ethernet',
        'show_sip'          => 'show_sip',
        'apply_sip'         => 'apply_sip',
        'show_callroutes'   => 'show_callroutes',
        'apply_callroutes'  => 'apply_callroutes',
        'show_log'          => 'show_log',
    );
}

sub cgiapp_postrun
{
    my $self = shift;
    my $content_ref = shift;
    $self->query()->charset('utf-8');
    my $tmpl = $self->load_tmpl('_template.html');
    $tmpl->param(
        content         => ${$content_ref},
        populate_uri    => $self->{__populate_uri}||'',
        submit_uri      => $self->{__submit_uri}||'',
        output          => $self->{__output}||'',
        );
    ${$content_ref} = $tmpl->output;
}

sub show_index
{
    my $self = shift;

    my $tmpl = $self->load_tmpl('index.html', die_on_bad_params => 0, global_vars => 1);
    return $tmpl->output;
}


use configuration;
use JSON;

sub save_configuration($$)
{
    my $name = shift;
    my $params = shift;
    my $json = objToJson($params);
    open(my $fh, '>', "$configuration::html_base/config/$name.json") or die $!;
    print $fh $json;
    close($fh);
}

sub get_params()
{
    my $self = shift;
    my $cgi = $self->query();
    my $params = {%{$cgi->Vars()}};
    
    # Make sure to not save these values in the .json configuration files.
    delete $params->{_apply};
    delete $params->{_method};
    return $params;
}

use CCN::MGW::probe;
use CCN::MGW::generate;

sub show_cards
{
    my $self = shift;
    my %cards = CCN::MGW::probe::cards();

    my @cards = map { $cards{$_} } sort keys %cards;

    my $tmpl = $self->load_tmpl('cards.html', die_on_bad_params => 0, global_vars => 1);
    $tmpl->param(cards => \@cards);
    $self->{__populate_uri} = 'config/cards.json';
    $self->{__submit_uri}   = 'index.pl';
    
    return $tmpl->output;
}

sub apply_cards
{
    my $self = shift;
    my $params = $self->get_params();

    # 1. Validate
    my $error_message = CCN::MGW::generate::run($params);
    warn($error_message), return
        if $error_message;

    # 2. Save
    save_configuration('cards',$params);
  
    # 3. Apply
    open( my $ph, "sudo '$configuration::perl_base/bin/cards_apply.sh' '$configuration::html_base' |");
    local $/; # slurp mode
    my $output = $self->query()->escapeHTML(<$ph>);
    close($ph);
    
    # 4. Return current values
    return "<h2>Changes attempted</h2><pre>$output</pre>";
}

# Ethernet interfaces

use CCN::Ethernet::generate;

sub show_ethernet
{
    my $self = shift;

    my @interfaces = CCN::Ethernet::probe::interfaces();
    
    my $name = 'ethernet';
    
    my $tmpl = $self->load_tmpl("$name.html", die_on_bad_params => 0, global_vars => 1);
    $tmpl->param(interfaces => \@interfaces);
    $self->{__populate_uri} = "config/$name.json";
    $self->{__submit_uri}   = 'index.pl';

    if(! -e "$configuration::html_base/config/$name.json")
    {
        # Default configuration to display (identical as system default)
        save_configuration($name,{
            eth1_mode => 'static',
            eth1_ipv4_address => '192.168.1.1',
            eth1_ipv4_netmask => '255.255.255.0',
            # No DHCP server on eth1 by default.
            eth2_mode => 'dhcp',
            eth3_mode => 'dhcp',
        });
    }

    return $tmpl->output;
}

sub apply_ethernet
{
    my $self = shift;
    my $params = $self->get_params();

    # 1. Validate
    my $error_message = CCN::Ethernet::generate::run($params);
    warn($error_message), return
        if $error_message;

    # 2. Save
    save_configuration('ethernet',$params);
  
    # 3. Apply
    open( my $ph, "sudo '$configuration::perl_base/bin/ethernet_apply.sh' '$configuration::html_base' |");
    local $/; # slurp mode
    my $output = $self->query()->escapeHTML(<$ph>);
    close($ph);
    
    # 4. Return current values
    return "<h2>Changes attempted</h2><pre>$output</pre>";
}

# SIP peers

use CCN::CallWeaver::generate;
use CCN::CallWeaver::probe;

sub show_sip
{
    my $self = shift;

    my @peers = CCN::CallWeaver::probe::peers();

    my $name = 'sip';

    my $tmpl = $self->load_tmpl("$name.html", die_on_bad_params => 0, global_vars => 1);
    $tmpl->param(sip_peers => \@peers);
    $self->{__populate_uri} = "config/$name.json";
    $self->{__submit_uri}   = 'index.pl';

    return $tmpl->output;
}

sub apply_sip
{
    my $self = shift;
    my $params = $self->get_params();

    # 1. Validate
    my $error_message = CCN::CallWeaver::generate::run_sip($params);
    warn($error_message), return
        if $error_message;

    # 2. Save
    save_configuration('sip',$params);
  
    # 3. Apply
    open( my $ph, "sudo '$configuration::perl_base/bin/sip_apply.sh' '$configuration::html_base' |");
    local $/; # slurp mode
    my $output = $self->query()->escapeHTML(<$ph>);
    close($ph);

    # 4. Return current values
    return "<h2>Changes attempted</h2><pre>$output</pre>";
}

# Call Routing

sub show_callroutes
{
    my $self = shift;

    my @routes = CCN::CallWeaver::probe::callroutes();

    my $name = 'callroutes';

    my $tmpl = $self->load_tmpl("$name.html", die_on_bad_params => 0);
    $tmpl->param(callroutes => \@routes);
    $self->{__populate_uri} = "config/$name.json";
    $self->{__submit_uri}   = 'index.pl';

    return $tmpl->output;
}

sub apply_callroutes
{
    my $self = shift;
    my $params = $self->get_params();

    # 1. Validate
    my $error_message = CCN::CallWeaver::generate::run_extensions($params);
    warn($error_message), return
        if $error_message;

    # 2. Save
    save_configuration('callroutes',$params);
  
    # 3. Apply
    open( my $ph, "sudo '$configuration::perl_base/bin/callroutes_apply.sh' '$configuration::html_base' |");
    local $/; # slurp mode
    my $output = $self->query()->escapeHTML(<$ph>);
    close($ph);

    # 4. Return current values
    return "<h2>Changes attempted</h2><pre>$output</pre>";
}


# Show logs (and other operations)

sub show_log
{
    my $self = shift;
    my $params = $self->get_params();

    my $log = $params->{log};

    my $file = {
        'ifconfig'  =>  '/sbin/ifconfig -a |',
        'tc_stats'  => "/sbin/tc -s qdisc |",
        'pstree'    =>  '/usr/bin/pstree |',
        'ps'        =>  '/bin/ps auxww |',
        'wanrouter_status' =>
            '('.
            join('', map { 'echo; echo '.ucfirst($_).'; echo; /bin/cat /proc/net/wanrouter/'.$_.'; echo; '}
                qw(status config interfaces map)).
            ' cd /proc/net/wanrouter; for name in wanpipe*; do echo; echo $name; echo; /bin/cat $name; echo; done'.
            ') |',
        'zaptel'    =>  '/bin/cat /proc/zaptel/* |',
        # These require "www-data" to be in group "callweaver" (see INSTALL).
        'show_channels'     => "sudo '$configuration::perl_base/bin/callweaver_command.sh' 'show channels' |",
        'zap_show_status'   => "sudo '$configuration::perl_base/bin/callweaver_command.sh' 'zap show status' |",
        'messages'          => "/var/log/messages",
        'wanrouter'         => "/var/log/wanrouter",
        'dmesg'             => "/bin/dmesg |",
        'bootup'            => "/var/log/dmesg",
        'callweaver_messages' => "/var/log/callweaver/messages",
        'callweaver_full'   => "/var/log/callweaver/full",
        'clear_cards'       => "/bin/rm '$configuration::html_base/config/cards.json' |",
        'clear_interfaces'  => "/bin/rm '$configuration::html_base/config/ethernet.json' |",
    }->{$log};

    return "<h2>Error</h2>" unless defined $file;

    open( my $ph, $file) or die "$file: $!";
    local $/; # slurp mode
    my $output = $self->query()->escapeHTML(<$ph>);
    close($ph);

    # 4. Return current values
    $self->{__output} = $output;
    return $self->show_index();
}

1;